#ifndef BANK_CLIENT_H
#define BANK_CLIENT_H

#include "Rpc.h"
#include <string>
#include <gtest/gtest.h>

class BankClient
  {
  public:
    /**
     * Create a bank client connecting to a BankServer frame
     * 
     * \param primarySvc the hostname of the primary Bank server
     * \param backupSvc the hostname of the backup Bank server
     */
    BankClient (std::string primarySvc, std::string backupSvc);
    virtual ~BankClient ();
    /**
     * Start running the client
     */
    void Run ();

  private:
    /// all possible actions a customer can do
    enum CustomerAction_t
      {
      Withdrawal=1,
      Deposit,
      Transfer,
      ReadBalance,
      Exit
      };

    /**
     * Ask for a csutomer to login by inputting a customer ID
     */
    void AskLogin ();
    /**
     * Ask customer to choose an action from a menu
     *
     * \return the action chosen
     */
    CustomerAction_t AskAction ();

    /**
     * Do the action chosen by the customer
     *
     * \param action the action chosen by the customer
     */
    void DoAction (CustomerAction_t action);

    /**
     * Switch the active server to another one
     *
     * \return true if the switching is done successfully; false otherwise
     */
    bool SwitchServer ();

    /**
     * Create a client handle to the server
     *
     * \param svc hostname of the server
     */
    bool CreateClient (std::string svc);
    /**
     * Call a client-side RPC function with error handling
     *
     * \param args RPC input argument
     * \param RpcFunc the client-side RPC function to be called
     *
     * \return false if RPC call failed or server logic failed; true otherwise
     */ 
    template <typename RET, typename ARGS> bool RpcCalling (ARGS args, RET* (*RpcFunc)(ARGS*,CLIENT*));

    /**
     * Do withdrawal
     *
     * \return true if the instruction is done successfully
     */
    bool DoWithdrawal ();
    /**
     * Do deposit
     *
     * \return true if the instruction is done successfully
     */
    bool DoDeposit ();
    /**
     * Do transfer
     *
     * \return true if the instruction is done successfully
     */
    bool DoTransfer ();
    /**
     * Do read balance
     *
     * \return true if the instruction is done successfully
     */
    bool DoReadBalance ();
    /**
     * Do create a customer
     *
     * \return true if the instruction is done successfully
     */
    bool DoCreateCustomer ();

    /// customer ID
    std::string m_cusId;
    /// true if primary is active; false if backup is active
    bool m_primaryIsActive;
    /// hostname of the primary Bank server
    std::string m_primarySvc;
    /// hostname of the backup Bank server
    std::string m_backupSvc;
    /// a handle for communicating with the active RPC server
    CLIENT* m_clnt;
  };


#endif /* ifndef BANK_CLIENT_H */
